#include <linux/module.h>
#include <linux/fs.h>         //defined file_operations
#include <linux/miscdevice.h> // defined miscdevice

#define MODULENAME "hellomisc"

#define LOG_INFO(fmt, ...) \
    printk(KERN_INFO "platformbus@"MODULENAME ": " fmt, ##__VA_ARGS__)

#define LOG_ERR(fmt, ...) \
    printk(KERN_ERR "platformbus@"MODULENAME ": " fmt, ##__VA_ARGS__)

static char kbuf[1024] = {"hello world!"};

extern unsigned int *vir_gpio5_dr; // IO端口映射到内核空间的虚拟地址

// open
static int misc_open(struct inode *inode,
                     struct file *filp)
{
    LOG_INFO("open");
    return 0;
}

// read
ssize_t misc_read(struct file *filp,
                  char __user *ubuf,
                  size_t count,
                  loff_t *f_pos)
{
    LOG_INFO("read");
    // copy data to user space
    ssize_t ret = count > strlen(kbuf) ? count : strlen(kbuf);
    unsigned long r = copy_to_user(ubuf, kbuf, ret);
    return ret - r;
}

// write
ssize_t misc_write(struct file *filp,
                   const char __user *ubuf,
                   size_t count,
                   loff_t *f_pos)
{
    LOG_INFO("write");
    // copy data from user space
    const size_t src_count = count;

    if (count > sizeof(kbuf))
        count = sizeof(kbuf);

    // r表示没有拷贝成功的字节数
    unsigned long r = copy_from_user(kbuf, ubuf, count);

    if (kbuf[0] == 1)
    {
        *vir_gpio5_dr |= (1 << 1);
    }
    else{
        *vir_gpio5_dr &= ~(1 << 1);
    }

    return src_count - (r + src_count - count);
}

// release
static int misc_release(struct inode *inode,
                        struct file *filp)
{
    LOG_INFO("release");
    return 0;
}

// file_operations
struct file_operations misc_fops = {
    .owner = THIS_MODULE,
    .open = misc_open,
    .read = misc_read,
    .write = misc_write,
    .release = misc_release,
};

struct miscdevice misc = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = "hellomisc",
    .fops = &misc_fops,
};